/*
 * @(#)SecureRandom.java	1.20 01/12/12
 *
 * 版权所有2002 Sun MicroSystems，Inc.保留所有权利。Sun专有/机密。使用受许可条款的约束。
 */

package java.security;

import java.util.*;

/**
 * 此类提供了一个基于SHA-1散列算法的加密强伪随机数生成器。
 *
 * 从随机继承的呼叫将在增强的功能方面实施。
 *
 * @see java.util.Random
 *
 * @version 1.2 96/09/15
 * @author Benjamin Renaud
 * @author Josh Bloch
 * @author Gadi Guy
 */

public class SecureRandom extends Random {

	/**
	 * 由空构造函数用来为构造中的SecureRandom设定种子。
	 */
	private static SecureRandom seeder;
	private static final int DIGEST_SIZE = 20;
	private transient MessageDigest digest;
	private byte[] state;
	private byte[] remainder;
	private int remCount;

	/**
	 * 这个空的构造函数会自动为生成器设定种子。我们尝试提供足够的种子字节来完全随机化生成器的内部状态(20个字节)。
	 * 然而，请注意，我们的种子生成算法尚未得到彻底研究或广泛部署。
	 *
	 * 在给定的虚拟机中第一次调用此构造函数时，可能需要几秒钟的CPU时间来设定生成器的种子，具体取决于底层硬件。
	 * 连续调用运行得很快，因为它们的种子位依赖于相同的(内部)伪随机数生成器。
	 *
	 * 此构造函数实现的种子设定过程确保每个SecureRandom实例生成的伪随机字节序列不会产生有关任何其他实例生成的字节序列的有用信息。
	 * 但是，如果用户希望生成具有真正无关种子的多个实例，则以下代码会产生所需的结果(每个实例的CPU成本相当高！)：
	 *
	 * <pre>
	 * SecureRandom rnd = new SecureRandom(SecureRandom.getSeed(20));
	 * </pre>
	 */
	public SecureRandom() {
		this(nextSeed());
	}

	/**
	 * 此调用由空构造函数独占使用，返回20个种子字节来为构造中的SecureRandom实例设定种子。
	 * 第一次调用此方法时，会创建一个类范围的生成器。这涉及使用getSeed生成20个“真实随机”字节，这非常耗时！
	 */
	private synchronized static byte[] nextSeed() {
		if (seeder == null) {
			seeder = new SecureRandom(getSeed(20));
			seeder.setSeed(SeedGenerator.getSystemEntropy());
		}

		byte seed[] = new byte[20];
		seeder.nextBytes(seed);
		return seed;
	}


	/**
	 * 此构造函数使用用户提供的种子，而不是空构造函数描述中引用的自设定种子算法。
	 * 如果调用方可以从某些物理设备(例如，辐射探测器或噪声二极管)访问高质量的随机字节，则它可能比空构造函数更可取。
	 *
	 * @param seed the seed.
	 */
	public SecureRandom(byte seed[]) {
		/*
		 * This call to our superclass constructor will result in a call
		 * to our own setSeed method, which will return immediately when
		 * it is passed zero.
		 */
		super(0);

		try {
			digest = MessageDigest.getInstance("SHA");
		} catch (NoSuchAlgorithmException e) {
			throw new InternalError("internal error: SHA-1 not available.");
		}

		setSeed(seed);
	}

	/**
	 * 重新设定此随机对象的种子。给定的种子是对现有种子的补充，而不是取代。因此，保证了重复呼叫永远不会减少随机性。
	 *
	 * @param seed the seed.
	 */
	synchronized public void setSeed(byte[] seed) {
		if (state != null) {
			digest.update(state);
			for (int i = 0; i < state.length; i++)
				state[i] = 0;
		}
		state = digest.digest(seed);
	}

	/**
	 * 使用给定的<code>长种子</code>中包含的8个字节重新设定这个随机对象的种子。
	 * 给定的种子是对现有种子的补充，而不是取代。因此，保证了重复呼叫永远不会减少随机性。
	 *
	 * <p>This method is defined for compatibility with
	 * <code>java.util.Random</code>.
	 *
	 * @param seed the seed.
	 */
	public void setSeed(long seed) {
		/*
		 * 忽略来自超级构造函数的调用(以及任何其他不幸传递0的调用)。重要的是，我们要忽略来自超类构造函数的调用，因为当时摘要还没有初始化。
		 */
		if (seed != 0)
			setSeed(longToByteArray(seed));
	}

	private static void updateState(byte[] state, byte[] output) {
		int last = 1;
		int v = 0;
		byte t = 0;
		boolean zf = false;

		// state(n + 1) = (state(n) + output(n) + 1) % 2^160;
		for (int i = 0; i < state.length; i++) {
			// Add two bytes
			v = (int)state[i] + (int)output[i] + last;
			// Result is lower 8 bits
			t = (byte)v;
			// Store result. Check for state collision.
			zf = zf | (state[i] != t);
			state[i] = t;
			// High 8 bits are carry. Store for next iteration.
			last = v >> 8;
		}

		// Make sure at least one bit changes!
		if (!zf)
			state[0]++;
	}

	/**
	 * 生成用户指定数量的随机字节数。此方法用作此类返回的所有随机实体(种子字节除外)的基础。因此，它可以被重写以更改类的行为。
	 *
	 * @param bytes the array to be filled in with random bytes.
	 */

	synchronized public void nextBytes(byte[] result) {
		int index = 0;
		int todo;
		byte[] output = remainder;

		// Use remainder from last time
		int r = remCount;
		if (r > 0) {
			// How many bytes?
			todo = (result.length - index) < (DIGEST_SIZE - r) ?
					(result.length - index) : (DIGEST_SIZE - r);
			// Copy the bytes, zero the buffer
			for (int i = 0; i < todo; i++) {
				result[i] = output[r];
				output[r++] = 0;
			}
			remCount += todo;
			index += todo;
		}

		// If we need more bytes, make them.
		while (index < result.length) {
			// Step the state
			digest.update(state);
			output = digest.digest();
			updateState(state, output);

			// How many bytes?
			todo = (result.length - index) > DIGEST_SIZE ?
					DIGEST_SIZE : result.length - index;
			// Copy the bytes, zero the buffer
			for (int i = 0; i < todo; i++) {
				result[index++] = output[i];
				output[i] = 0;
			}
			remCount += todo;
		}

		// Store remainder for next time
		remainder = output;
		remCount %= DIGEST_SIZE;
	}

	/**
	 * 生成一个整数，该整数包含用户指定的伪随机位数(右对齐，带有前导零)。此方法覆盖<code>java.util.Random</code>方法，
	 * 并为从该类继承的所有方法(例如，<code>nextInt</code>、<code>nextLong</code>和<code>nextFloat</code>)提供随机位来源。
	 *
	 * @param numBits number of pseudo-random bits to be generated, where
	 * 0 <= <code>numBits</code> <= 32.
	 */
	final protected int next(int numBits) {
		int numBytes = (numBits+7)/8;
		byte b[] = new byte[numBytes];
		int next = 0;

		nextBytes(b);
		for (int i=0; i<numBytes; i++)
			next = (next << 8) + (b[i] & 0xFF);

		return next >>> (numBytes*8 - numBits);
	}

	/**
	 * 返回给定的种子字节数，该数是使用此类用于为自身设定种子的种子生成算法计算得出的。此调用可用于设定其他随机数生成器的种子。
	 * 虽然我们试图返回“真正随机”的字节序列，但我们不知道此调用返回的字节有多随机。
	 * (有关底层算法的简要说明，请参阅空构造函数<a href>SecureRandom</a>。)。
	 * 谨慎的用户会犯错误，并获得额外的种子字节，尽管应该注意，种子生成的成本较高。
	 *
	 * @param numBytes the number of seed bytes to generate.
	 *
	 * @return the seed bytes.
	 */
	public static byte[] getSeed(int numBytes) {
		byte[] retVal = new byte[numBytes];

		for (int i=0; i<numBytes; i++)
			retVal[i] = (byte) SeedGenerator.getByte();

		return retVal;
	}


	/**
	 * Helper function to convert a long into a byte array (least significant
	 * byte first).
	 */
	private static byte[] longToByteArray(long l) {
		byte[] retVal = new byte[8];

		for (int i=0; i<8; i++) {
			retVal[i] = (byte) l;
			l >>= 8;
		}

		return retVal;
	}
}
